package cn.shadow.module.snake;

import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.scenes.scene2d.actions.MoveToAction;

import java.util.HashMap;
import java.util.Map;


/**
 * 蛇的身体节点
 */
public class SnakeNode extends Actor {

    private TextureRegion display;
    private NodeType type;
    private float x;
    private float y;
    private int bodyX;
    private int bodyY;

    private float lastX;
    private float lastY;
    /**
     * 相对角度
     */
    private float degree;
    /**
     * 前一个节点
     */
    private SnakeNode preNode;
    /**
     * 头节点
     */
    private SnakeNode headNode;

    /**
     * 方向
     */
    private Direction direction;

    /**
     * 暂停
     */
    private boolean pause;

    private int speedValue;


    public float getDegree() {
        return degree;
    }

    public void setDegree(float degree) {
        this.degree = degree;
    }

    public SnakeNode(NodeType type, TextureRegion display) {
        this.type = type;
        this.display = display;
        this.direction = randDirection();
        setSize(this.display.getRegionWidth(), this.display.getRegionHeight());
        this.bodyX = display.getRegionWidth();
        this.bodyY = display.getRegionHeight();
        this.speedValue = 6;
    }

    public SnakeNode getPreNode() {
        return preNode;
    }

    public void setPreNode(SnakeNode preNode) {
        this.preNode = preNode;
    }

    public SnakeNode getHeadNode() {
        return headNode;
    }

    public void setHeadNode(SnakeNode headNode) {
        this.headNode = headNode;
    }

    public void setPause(boolean pause) {
        this.pause = pause;
    }

    public boolean isPause() {
        return pause;
    }

    public int getBodyX() {
        return bodyX;
    }

    public void setBodyX(int bodyX) {
        this.bodyX = bodyX;
    }

    public int getBodyY() {
        return bodyY;
    }

    public void setBodyY(int bodyY) {
        this.bodyY = bodyY;
    }

    public float getLastX() {
        return lastX;
    }

    public void setLastX(float lastX) {
        this.lastX = lastX;
    }

    public float getLastY() {
        return lastY;
    }

    public void setLastY(float lastY) {
        this.lastY = lastY;
    }

    public int getSpeedValue() {
        return speedValue;
    }

    public void setSpeedValue(int speedValue) {
        if (speedValue <= 0) {
            speedValue = 1;
        } else if (speedValue > 20) {
            speedValue = 20;
        }
        this.speedValue = speedValue;
    }

    @Override
    public void act(float delta) {
        if (isInPauseState()) {  //如果暂停
            return; //直接返回
        }
        super.act(delta);
        move();
        if (type == NodeType.HEAD) {
            MoveToAction action = Actions.moveTo(x, y, 0);
            this.addAction(action);
        } else {
            float x = preNode.getLastX();  //前一节上次的坐标
            float y = preNode.getLastY();
            float duration = headNode == null ? this.duration() : headNode.duration();
            MoveToAction action = Actions.moveTo(x, y, duration);
            this.addAction(action);
        }
        setLastX(x); //将上次的位置保存下来
        setLastY(y);
    }

    private boolean isInPauseState() {
        return isHead() ? isPause() : headNode.isPause();
    }

    public float duration() {
        switch (speedValue) {
            case 1:
                return 2.0f;
            case 2:
                return 0.9f;
            case 3:
                return 0.8f;
            case 4:
                return 0.7f;
            case 5:
                return 0.6f;
            case 6:
                return 0.5F;
            case 7:
                return 0.45F;
            case 8:
                return 0.4F;
            case 9:
                return 0.35F;
            case 10:
                return 0.3F;
            default:
                if (speedValue<15)
                return 0.25f;
                else return 0.15f;
        }
    }
    public static float calAngle(double x1, double y1, double x2, double y2) {
        double x = x2 - x1;
        double y = y2 - y1;
        double z = Math.sqrt(x * x + y * y);
        return (float) (Math.asin(y / z));
    }

    public void move() {
        this.x = getX(); //先拿到当前位置坐标
        this.y = getY();
        if (isHead()) {
/*            float dx = (Gdx.input.getX() - x);
            float dy = (Gdx.input.getY() - y);
            Vector2 vector2=new Vector2(dx,dy);
            float angle = vector2.angle();
//            float angle = calAngle(x, y, Gdx.input.getX(), Gdx.input.getY());
            float addX = speedValue * MathUtils.sin(angle);
            float addY = speedValue * MathUtils.cos(angle);
            System.out.println("degree:"+angle);
            System.out.println(String.format("dx=%s,dy=%s", dx, dy));
            x -= addX;
            y -= addY;
//            this.setRotation(angle);
            this.setDegree(angle);
            this.moveBy(addX,addY);*/
            switch (direction) {
                case UP:
                    y += speedValue;
                    break;
                case DOWN:
                    y -= speedValue;
                    break;
                case LEFT:
                    x -= speedValue;
                    break;
                case RIGHT:
                    x += speedValue;
                    break;
            }
        }
    }


    /**
     * 向上
     */
    public void turnUp() {
        if (isHead()) {
            if (direction == Direction.UP || direction == Direction.DOWN) {
                return;
            }
            direction = Direction.UP;
        }
    }

    /**
     * 向下
     */
    public void turnDown() {
        if (isHead()) {
            if (direction == Direction.UP || direction == Direction.DOWN) {
                return;
            }
            direction = Direction.DOWN;
        }
    }

    /**
     * 向左
     */
    public void turnLeft() {
        if (isHead()) {
            if (direction == Direction.RIGHT || direction == Direction.LEFT) {
                return;
            }
            direction = Direction.LEFT;
        }
    }

    /**
     * 向右
     */
    public void turnRight() {
        if (isHead()) {
            if (direction == Direction.RIGHT || direction == Direction.LEFT) {
                return;
            }
            direction = Direction.RIGHT;
        }
    }

    public boolean isHead() {
        return type == NodeType.HEAD;
    }

    public void changeDirection(float width, float height) {
        if (isHead()) {
            this.x = getX();
            this.y = getY();
            if ((x + bodyX) > width) {
                x = 0;
            } else if ((x - bodyX < 0)) {
                x = width - bodyY;
            } else if ((y + bodyY) > height) {
                y = 0;
            } else if ((y - bodyY < 0)) {
                y = height - bodyY;
            }
        }
    }

    public boolean overRanged(float width, float height) {
        if (isHead()) {
            this.x = getX();
            this.y = getY();
            return (x + bodyX) > width || (x < 0) || (y + bodyY) > height || (y < 0);
        }
        return false;
    }


    enum NodeType {
        HEAD(1, "头"), BODY(0, "身体"), TAIL(2, "尾巴");
        int type;
        String des;

        NodeType(int type, String des) {
            this.type = type;
            this.des = des;
        }
    }

    public static Map<Integer, Direction> map = new HashMap<>();

    public static Direction randDirection() {
        int rand = (int) (Math.random() * Direction.values().length) + 1;
        return map.get(rand);
    }

    enum Direction {
        UP(1, "上"), DOWN(2, "下"), LEFT(3, "左"), RIGHT(4, "右");
        int type;
        String des;

        Direction(int type, String des) {
            this.type = type;
            this.des = des;
            map.put(type, this);
        }
    }

    /**
     * 绘制演员
     *
     * @param batch       纹理画布, 用于绘制演员封装的纹理。SpriteBatch 就是实现了 Batch 接口
     * @param parentAlpha 父节点的透明度, 处理透明度和演员的颜色属性有关, 稍微复杂, 这里暂时先不处理
     */
    @Override
    public void draw(Batch batch, float parentAlpha) {
        super.draw(batch, parentAlpha);
        // 如果 region 为 null 或者 演员不可见, 则直接不绘制
        if (display == null || !isVisible()) {
            return;
        }
        batch.draw(
                display,
                getX(), getY(),
                getOriginX(), getOriginY(),
                getWidth(), getHeight(),
                getScaleX(), getScaleY(),
                getRotation()
        );
    }

    public TextureRegion getDisplay() {
        return display;
    }

    public void setDisplay(TextureRegion display) {
        this.display = display;
    }

    public NodeType getType() {
        return type;
    }

    public void setType(NodeType type) {
        this.type = type;
    }

    public Direction getDirection() {
        return direction;
    }

    public void setDirection(Direction direction) {
        this.direction = direction;
    }


    public static void main(String[] args) {
        Vector2 vector3 =new Vector2(50,50);
        float angle = vector3.angle();
        float cos = MathUtils.cos((float) (angle / Math.PI * 180));
        float sin = MathUtils.sin((float) (angle / Math.PI * 180));
        System.out.println(angle);
        System.out.println(cos);
        System.out.println(sin);
    }

}
